/*
 * Copyright 2011 Katsunori Koyanagi
 *
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */

package sweezy.core.utils
{
	import flash.display.Loader;
	import flash.display.LoaderInfo;
	import flash.display.MovieClip;
	import flash.events.Event;
	import flash.utils.ByteArray;

	public class EventLoop
	{

		private static var _count:uint;

		private static var _head:Node;

		private static var _initialized:Boolean;

		private static var _mc:MovieClip;

		private static var _tail:Node;

		public static function addHandler(handler:Function):void
		{
			if (handler === null)
			{
				return;
			}
			if (!_initialized)
			{
				_initialized = true;
				init();
			}

			var node:Node = Node.checkout();
			node.prev = _tail.prev;
			node.prev.next = node;
			node.next = _tail;
			node.handler = handler;
			_tail.prev = node;

			if (++_count === 1 && _mc !== null)
			{
				_mc.play();
			}
		}

		public static function removeHandler(handler:Function):void
		{
			if (handler === null || _count === 0)
			{
				return;
			}

			var node:Node = _head.next;
			while (node !== _tail)
			{
				if (node.handler !== handler)
				{
					node = node.next;
					continue;
				}

				node.disposed = true;
				break;
			}
		}

		private static function dummyHandler():void
		{
		}

		private static function handler():void
		{
			var node:Node = _head.next;
			while (node !== _tail)
			{
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
				if (node.disposed)
				{
					node = Node.checkin(node);
					--_count;
				}
				else
				{
					node.handler();
					node = node.next;
				}
			}

			if (_count === 0)
			{
				_mc.stop();
			}
		}

		private static function init():void
		{
			_head = new Node();
			_tail = new Node();

			_head.next = _tail;
			_tail.next = _tail;
			_tail.prev = _head;
			_tail.handler = dummyHandler;

			var bytes:ByteArray = new ByteArray();
			bytes.writeDouble(7.39178396813916e+30);
			bytes.writeDouble(2.2039319854937993e-317);
			bytes.writeDouble(1.3580980288329204e-312);
			bytes.writeByte(0);

			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.INIT, initHandler);
			loader.loadBytes(bytes);
		}

		private static function initHandler(e:Event):void
		{
			var info:LoaderInfo = e.currentTarget as LoaderInfo;
			info.removeEventListener(Event.INIT, initHandler);

			_mc = info.loader.content as MovieClip;
			_mc.addFrameScript(0, handler, 1, handler);

			if (_count === 0)
			{
				_mc.stop();
			}
		}
	}
}

import flash.utils.Dictionary;

class Node
{

	private static var _pool:Dictionary = new Dictionary(true);

	public static function checkin(node:Node):Node
	{
		node.next.prev = node.prev;
		node.prev.next = node.next;

		var next:Node = node.next;

		node.next = null;
		node.prev = null;
		node.handler = null;
		node.disposed = false;
		_pool[node] = null;

		return next;
	}

	public static function checkout():Node
	{
		for (var node:Object in _pool)
		{
			delete _pool[node];
			return node as Node;
		}

		return new Node();
	}

	public var disposed:Boolean;

	public var handler:Function;

	public var next:Node;

	public var prev:Node;
}
